#!/usr/bin/env python3
"""
PLOOP数据处理器 - 基于IDA Pro分析的SET2D算法实现
处理带FRADIUS的顶点数据，生成平滑截面profile
"""

import math
import re
from typing import List, Tuple, Optional
from dataclasses import dataclass

@dataclass
class Vertex:
    """顶点数据结构"""
    x: float
    y: float
    z: float
    fradius: Optional[float] = None
    
    def __str__(self):
        if self.fradius:
            return f"({self.x:.2f}, {self.y:.2f}, {self.z:.2f}, FRAD:{self.fradius:.2f})"
        return f"({self.x:.2f}, {self.y:.2f}, {self.z:.2f})"

@dataclass
class PLoop:
    """PLOOP数据结构"""
    name: str
    height: float
    vertices: List[Vertex]
    
    def __str__(self):
        return f"PLOOP {self.name}: H={self.height}, {len(self.vertices)} vertices"

class PLoopProcessor:
    """PLOOP处理器 - 实现SET2D算法"""
    
    def __init__(self, tolerance: float = 0.001):
        self.tolerance = tolerance
    
    def parse_position(self, pos_str: str) -> Tuple[float, float, float]:
        """解析位置字符串 POS E 0mm N 2949.5mm U 0mm"""
        x, y, z = 0.0, 0.0, 0.0
        
        # 解析E/W方向（X轴）
        e_match = re.search(r'E\s+([\d.-]+)mm', pos_str)
        w_match = re.search(r'W\s+([\d.-]+)mm', pos_str)
        if e_match:
            x = float(e_match.group(1))
        elif w_match:
            x = -float(w_match.group(1))
        
        # 解析N/S方向（Y轴）
        n_match = re.search(r'N\s+([\d.-]+)mm', pos_str)
        s_match = re.search(r'S\s+([\d.-]+)mm', pos_str)
        if n_match:
            y = float(n_match.group(1))
        elif s_match:
            y = -float(s_match.group(1))
        
        # 解析U方向（Z轴）
        u_match = re.search(r'U\s+([\d.-]+)mm', pos_str)
        if u_match:
            z = float(u_match.group(1))
        
        return x, y, z
    
    def parse_file(self, content: str) -> List[PLoop]:
        """解析PLOOP文件"""
        ploops = []
        lines = content.split('\n')
        
        current_ploop = None
        current_vertex = None
        framework_name = "Unknown"
        
        for line_num, line in enumerate(lines, 1):
            line = line.strip()
            
            # 检测FRMWORK名称
            if line.startswith('NEW FRMWORK'):
                parts = line.split()
                framework_name = parts[2] if len(parts) > 2 else f"Framework_{line_num}"
            
            # 检测PLOOP开始
            elif line == 'NEW PLOOP':
                current_ploop = {'name': framework_name, 'vertices': [], 'height': 0.0}
            
            # 检测PLOOP高度
            elif line.startswith('HEIG') and current_ploop is not None:
                height_match = re.search(r'HEIG\s+([\d.-]+)mm', line)
                if height_match:
                    current_ploop['height'] = float(height_match.group(1))
            
            # 检测顶点开始
            elif line == 'NEW PAVERT':
                current_vertex = {'x': 0.0, 'y': 0.0, 'z': 0.0, 'fradius': None}
            
            # 检测位置信息
            elif line.startswith('POS') and current_vertex is not None:
                x, y, z = self.parse_position(line)
                current_vertex.update({'x': x, 'y': y, 'z': z})
            
            # 检测圆角半径
            elif line.startswith('FRAD') and current_vertex is not None:
                frad_match = re.search(r'FRAD\s+([\d.-]+)mm', line)
                if frad_match:
                    current_vertex['fradius'] = float(frad_match.group(1))
            
            # 检测顶点结束
            elif line == 'END' and current_vertex is not None:
                vertex = Vertex(
                    x=current_vertex['x'],
                    y=current_vertex['y'], 
                    z=current_vertex['z'],
                    fradius=current_vertex['fradius']
                )
                current_ploop['vertices'].append(vertex)
                current_vertex = None
        
        # 处理最后的PLOOP
        if current_ploop is not None and len(current_ploop['vertices']) > 2:
            ploop = PLoop(
                name=current_ploop['name'],
                height=current_ploop['height'],
                vertices=current_ploop['vertices']
            )
            ploops.append(ploop)
        
        return ploops
    
    def calculate_fillet_arc(self, prev_vertex: Vertex, vertex: Vertex, next_vertex: Vertex) -> List[Vertex]:
        """计算内切圆弧顶点 - 基于SET2D算法"""
        if vertex.fradius is None or vertex.fradius <= 0:
            return [vertex]
        
        # 计算前后边的向量
        v1_x = vertex.x - prev_vertex.x
        v1_y = vertex.y - prev_vertex.y
        v2_x = next_vertex.x - vertex.x  
        v2_y = next_vertex.y - vertex.y
        
        # 标准化向量
        len1 = math.sqrt(v1_x*v1_x + v1_y*v1_y)
        len2 = math.sqrt(v2_x*v2_x + v2_y*v2_y)
        
        if len1 < self.tolerance or len2 < self.tolerance:
            return [vertex]
        
        v1_x /= len1
        v1_y /= len1
        v2_x /= len2
        v2_y /= len2
        
        # 计算夹角的一半
        dot_product = v1_x * v2_x + v1_y * v2_y
        dot_product = max(-1.0, min(1.0, dot_product))  # 限制范围
        
        half_angle = math.acos(abs(dot_product)) / 2.0
        
        if half_angle < 0.001:  # 角度太小，跳过圆角
            return [vertex]
        
        # 计算到切点的距离
        tan_half = math.tan(half_angle)
        if tan_half < self.tolerance:
            return [vertex]
        
        dist_to_tangent = vertex.fradius / tan_half
        
        # 限制切点距离，防止超出边长
        max_dist1 = len1 * 0.9
        max_dist2 = len2 * 0.9
        dist_to_tangent = min(dist_to_tangent, max_dist1, max_dist2)
        
        # 计算两个切点
        tangent1_x = vertex.x - v1_x * dist_to_tangent
        tangent1_y = vertex.y - v1_y * dist_to_tangent
        tangent2_x = vertex.x + v2_x * dist_to_tangent
        tangent2_y = vertex.y + v2_y * dist_to_tangent
        
        # 计算圆心（角平分线方向）
        bisector_x = v1_x + v2_x
        bisector_y = v1_y + v2_y
        bisector_len = math.sqrt(bisector_x*bisector_x + bisector_y*bisector_y)
        
        if bisector_len < self.tolerance:
            return [vertex]
        
        bisector_x /= bisector_len
        bisector_y /= bisector_len
        
        # 判断凸凹性（叉积）
        cross_product = v1_x * v2_y - v1_y * v2_x
        radius_sign = 1.0 if cross_product > 0 else -1.0
        
        center_dist = vertex.fradius / math.sin(half_angle)
        center_x = vertex.x + bisector_x * center_dist * radius_sign
        center_y = vertex.y + bisector_y * center_dist * radius_sign
        
        # 生成圆弧顶点
        arc_vertices = []
        
        # 添加第一个切点
        arc_vertices.append(Vertex(tangent1_x, tangent1_y, vertex.z))
        
        # 计算圆弧角度
        angle1 = math.atan2(tangent1_y - center_y, tangent1_x - center_x)
        angle2 = math.atan2(tangent2_y - center_y, tangent2_x - center_x)
        
        # 确定扫描方向
        angle_diff = angle2 - angle1
        if abs(angle_diff) > math.pi:
            if angle_diff > 0:
                angle_diff -= 2 * math.pi
            else:
                angle_diff += 2 * math.pi
        
        # 根据圆弧长度确定分段数
        arc_length = abs(angle_diff) * vertex.fradius
        num_segments = max(2, int(arc_length / 100.0))  # 每100mm一个分段
        
        # 生成中间圆弧点
        for i in range(1, num_segments):
            t = i / num_segments
            current_angle = angle1 + angle_diff * t
            arc_x = center_x + vertex.fradius * math.cos(current_angle)
            arc_y = center_y + vertex.fradius * math.sin(current_angle)
            arc_vertices.append(Vertex(arc_x, arc_y, vertex.z))
        
        # 添加第二个切点
        arc_vertices.append(Vertex(tangent2_x, tangent2_y, vertex.z))
        
        return arc_vertices
    
    def process_ploop(self, ploop: PLoop) -> List[Vertex]:
        """处理PLOOP，生成最终的profile顶点"""
        if len(ploop.vertices) < 3:
            return ploop.vertices
        
        processed_vertices = []
        n = len(ploop.vertices)
        
        # 确保首尾闭合
        vertices = ploop.vertices[:]
        if (abs(vertices[0].x - vertices[-1].x) > self.tolerance or 
            abs(vertices[0].y - vertices[-1].y) > self.tolerance):
            vertices.append(vertices[0])  # 闭合多边形
        
        n = len(vertices)
        
        for i in range(n - 1):  # 跳过最后一个重复点
            current = vertices[i]
            prev_vertex = vertices[i - 1] if i > 0 else vertices[n - 2]
            next_vertex = vertices[i + 1]
            
            # 处理圆角
            arc_vertices = self.calculate_fillet_arc(prev_vertex, current, next_vertex)
            processed_vertices.extend(arc_vertices)
        
        return processed_vertices
    
    def generate_profile_report(self, ploop: PLoop, processed_vertices: List[Vertex]) -> str:
        """生成详细的profile报告"""
        report = []
        report.append("=" * 80)
        report.append(f"PLOOP PROFILE REPORT: {ploop.name}")
        report.append("=" * 80)
        report.append(f"Height: {ploop.height}mm")
        report.append(f"Original vertices: {len(ploop.vertices)}")
        report.append(f"Processed vertices: {len(processed_vertices)}")
        report.append("")
        
        # 统计圆角信息
        fradius_count = sum(1 for v in ploop.vertices if v.fradius is not None)
        if fradius_count > 0:
            report.append(f"FRADIUS处理: {fradius_count} 个圆角顶点")
            for i, v in enumerate(ploop.vertices):
                if v.fradius:
                    report.append(f"  顶点[{i}]: 圆角半径 {v.fradius}mm")
        report.append("")
        
        # 原始顶点列表
        report.append("原始顶点坐标:")
        for i, v in enumerate(ploop.vertices):
            report.append(f"  [{i:2d}] {v}")
        report.append("")
        
        # 处理后的顶点列表
        report.append("最终Profile顶点坐标:")
        for i, v in enumerate(processed_vertices):
            report.append(f"  [{i:3d}] {v}")
        report.append("")
        
        # 计算几何信息
        if processed_vertices:
            x_coords = [v.x for v in processed_vertices]
            y_coords = [v.y for v in processed_vertices]
            
            bounds = {
                'min_x': min(x_coords),
                'max_x': max(x_coords),
                'min_y': min(y_coords), 
                'max_y': max(y_coords),
                'width': max(x_coords) - min(x_coords),
                'height': max(y_coords) - min(y_coords)
            }
            
            report.append("几何边界信息:")
            report.append(f"  X范围: {bounds['min_x']:.2f} ~ {bounds['max_x']:.2f} mm (宽度: {bounds['width']:.2f}mm)")
            report.append(f"  Y范围: {bounds['min_y']:.2f} ~ {bounds['max_y']:.2f} mm (高度: {bounds['height']:.2f}mm)")
        
        report.append("=" * 80)
        return "\n".join(report)

def main():
    """主函数"""
    processor = PLoopProcessor()
    
    # 读取文件
    try:
        with open('717.txt', 'r', encoding='utf-8') as f:
            content = f.read()
        print(f"文件读取成功，内容长度: {len(content)} 字符")
    except FileNotFoundError:
        print("错误: 找不到文件 717.txt")
        return
    except Exception as e:
        print(f"读取文件时出错: {e}")
        return
    
    # 解析PLOOP数据
    print("开始解析PLOOP数据...")
    ploops = processor.parse_file(content)
    print(f"解析完成，发现 {len(ploops)} 个PLOOP")
    
    if len(ploops) == 0:
        print("警告: 没有找到任何有效的PLOOP数据")
        # 显示文件的前几行以便调试
        lines = content.split('\n')
        print("文件前20行内容:")
        for i, line in enumerate(lines[:20]):
            print(f"  {i+1}: {line}")
        return
    
    print()
    
    # 处理每个PLOOP
    for i, ploop in enumerate(ploops):
        print(f"处理PLOOP {i+1}/{len(ploops)}: {ploop.name}")
        
        # 生成profile
        processed_vertices = processor.process_ploop(ploop)
        
        # 生成报告
        report = processor.generate_profile_report(ploop, processed_vertices)
        print(report)
        print()
        
        # 只显示前3个详细结果，避免输出过长
        if i >= 2:
            print(f"... 还有 {len(ploops) - i - 1} 个PLOOP未显示")
            break

if __name__ == "__main__":
    main() 